package com.starry.module.system.core.oauth2.authorization.utils;

import cn.hutool.json.JSONUtil;
import com.starry.core.security.utils.SecurityErrorUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.util.Map;

/**
 * 认证鉴权工具
 *
 * @author 小柯
 */
@Slf4j
public class SecurityUtils extends SecurityErrorUtil {

    private SecurityUtils() {
        // 禁止实例化工具类
        throw new UnsupportedOperationException("Utility classes cannot be instantiated.");
    }

    /**
     * 从认证信息中获取客户端token
     *
     * @param authentication 认证信息
     * @return 客户端认证信息，获取失败抛出异常
     */
    public static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
        OAuth2ClientAuthenticationToken clientPrincipal = null;
        if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
            clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
        }
        if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
            return clientPrincipal;
        }
        throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
    }

    /**
     * 提取请求中的参数并转为一个map返回
     *
     * @param request 当前请求
     * @return 请求中的参数
     */
    public static MultiValueMap<String, String> getSchemas(HttpServletRequest request) {
        Map<String, String[]> SchemaMap = request.getParameterMap();
        MultiValueMap<String, String> Schemas = new LinkedMultiValueMap<>(SchemaMap.size());
        SchemaMap.forEach((key, values) -> {
            for (String value : values) {
                Schemas.add(key, value);
            }
        });
        return Schemas;
    }

    /**
     * 抛出 OAuth2AuthenticationException 异常
     *
     * @param errorCode 错误码
     * @param message   错误信息
     * @param errorUri  错误对照地址
     */
    public static void throwError(String errorCode, String message, String errorUri) {
        OAuth2Error error = new OAuth2Error(errorCode, message, errorUri);
        throw new OAuth2AuthenticationException(error);
    }

    /**
     * 写回信息
     *
     * @param data     响应数据
     * @param response 当前响应
     */
    public static void writeResponse(Object data, HttpServletResponse response) {
        try {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(JSONUtil.toJsonStr(data));
            response.getWriter().flush();
            response.getWriter().close();
        } catch (Exception e) {
            log.error("写回信息失败", e);
        }
    }

}
